<?PHP
#
#   FILE:  Collage.php
#
#   A plugin for the Metavus digital collections platform
#   Copyright 2021-2022 Edward Almasy and Internet Scout Research Group
#   http://metavus.net
#
# @scout:phpstan

namespace Metavus\Plugins;

use Metavus\MetadataSchema;
use Metavus\Plugins\Collage\RecordImageCollage;
use Metavus\Record;
use Metavus\RecordFactory;
use Metavus\SearchEngine;
use Metavus\User;
use ScoutLib\ApplicationFramework;
use ScoutLib\Plugin;
use ScoutLib\SearchParameterSet;

/**
 * Create an insertion keyword that can be used to request
 *  a collage of records based on user-configurable search
 */
class Collage extends Plugin
{
    # ---- STANDARD PLUGIN INTERFACE -----------------------------------------

    /**
     * Set the plugin attributes.
     */
    public function register()
    {
        $this->Name = "Collage";
        $this->Version = "1.0.0";
        $this->Description = "Add a resource collage on keyword insertion with ".
            "user defined search parameters for resource selection.";
        $this->Author = "Internet Scout";
        $this->Url = "http://metavus.net";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = [
            "MetavusCore" => "1.0.0",
        ];
        $this->EnabledByDefault = true;
        $this->CfgSetup["TileWidth"] = [
            "Type" => "Number",
            "Label" => "Tile Length",
            "Help" => "Width/height (in pixels) for collage image tile.",
            "Default" => 150
        ];
        $this->CfgSetup["NumRows"] = [
            "Type" => "Number",
            "Label" => "Number of Rows",
            "Help" => "How many rows of images should be in the collage.",
            "Default" => 3
        ];
        $this->CfgSetup["MaxExpectedViewportWidth"] = [
            "Type" => "Number",
            "Label" => "Max Expected Screen Width",
            "Help" => "Maximum expected width of any given user's monitor in pixels.",
            "Default" => 1920
        ];
        $this->CfgSetup["DialogWidth"] = [
            "Type" => "Number",
            "Label" => "Dialog Width",
            "Help" => "Width (in pixels) for popup that displays when tile is clicked.",
            "Default" => 600
        ];
    }

    /**
     * Set up keyword for inserting resource collage
     * @return string|null error string or null on success
     */
    public function initialize()
    {
        $GLOBALS["AF"]->registerInsertionKeywordCallback(
            "RESOURCECOLLAGE-DISPLAYCOLLAGE",
            [$this, "getCollageHtml"],
            ["SchemaId"]
        );

        return null;
    }

    /**
     * Set up configuration options.
     */
    public function setUpConfigOptions()
    {
        # get the list of schemas
        $Schemas = MetadataSchema::getAllSchemas();
        # filter out user schema
        unset($Schemas[MetadataSchema::SCHEMAID_USER]);
        foreach ($Schemas as $TypeSchemaId => $TypeSchema) {
            $this->CfgSetup["DisplayResources_".$TypeSchemaId] = [
                "Type" => "Search Parameters",
                "Label" => $TypeSchema->name()." Search Parameters",
                "Help" => "Search parameters that define which records of type ".
                    $TypeSchema->name()." to display in the collage."
            ];
        }

        return null;
    }


    # ---- HOOKED METHODS ----------------------------------------------------


    # ---- CALLABLE METHODS --------------------------------------------------

    /**
     * Get resource collage html for this plugin's config settings
     * @param int $SchemaId ID of schema to grab collage for
     * @return string html for collage, may be empty if no resources have
     *  screenshots on this site.
     */
    public function getCollageHtml(int $SchemaId)
    {
        # get mapped screenshot field
        # (in case of non-default schema with different screenshot field)
        $Schema = new MetadataSchema($SchemaId);
        $ScreenshotField = $Schema->getFieldByMappedName("Screenshot");

        # generate search parameters with requirement that there is a
        #       screenshot (plus user params)
        $SearchParams = new SearchParameterSet();
        $SearchParams->addParameter("=1", $ScreenshotField);
        $SearchParams->logic("AND");
        $SearchParams->itemTypes($SchemaId);
        $SearchParamsWithUserSet = clone $SearchParams;
        if (!is_null($this->configSetting("DisplayResources_".$SchemaId))) {
            $SearchParamsWithUserSet->addSet(
                $this->configSetting("DisplayResources_".$SchemaId)
            );
        }

        $Engine = new SearchEngine();
        $SearchResults = $Engine->search($SearchParamsWithUserSet);

        $RecordIds = array_keys($SearchResults);
        $RFactory = new RecordFactory($SchemaId);
        $User = User::getCurrentUser();
        $NumberOfImages = $this->getNumberOfImages();
        $RecordIds = $RFactory->getFirstNViewableRecords(
            $RecordIds,
            $User,
            $NumberOfImages
        );

        # if there were no relevant resources, grab any resources with screenshots
        if (count($RecordIds) == 0) {
            $SearchResults = $Engine->search($SearchParams);
            $RecordIds = array_keys($SearchResults);
            $RecordIds = $RFactory->getFirstNViewableRecords(
                $RecordIds,
                $User,
                $NumberOfImages
            );
        }

        $RecordImageCollage = new RecordImageCollage($RecordIds);
        return $RecordImageCollage->getHtml();
    }

    /**
     * Get number of images in collage.
     * @return int Number of images in collage.
     */
    public function getNumberOfImages(): int
    {
        $TileWidth = $this->configSetting("TileWidth");
        $NumRows = $this->configSetting("NumRows");
        $ViewportWidth = $this->configSetting("MaxExpectedViewportWidth");
        return (int)ceil($ViewportWidth / $TileWidth) * $NumRows;
    }
}
